package com.example.blog.service.impl;

import com.example.blog.dto.ContentAuditDTO;
import com.example.blog.entity.ContentAudit;
import com.example.blog.entity.User;
import com.example.blog.exception.ResourceNotFoundException;
import com.example.blog.repository.ContentAuditRepository;
import com.example.blog.repository.UserRepository;
import com.example.blog.service.ContentAuditService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service
public class ContentAuditServiceImpl implements ContentAuditService {
    @Autowired
    private ContentAuditRepository contentAuditRepository;

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public ContentAuditDTO submitForAudit(ContentAuditDTO auditDTO) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        User submitter = userRepository.findByUsername(username)
                .orElseThrow(() -> new ResourceNotFoundException("User", "username", username));

        ContentAudit audit = new ContentAudit();
        audit.setType(auditDTO.getType());
        audit.setContentId(auditDTO.getContentId());
        audit.setTitle(auditDTO.getTitle());
        audit.setContent(auditDTO.getContent());
        audit.setSubmitter(submitter);
        audit.setStatus("PENDING");

        return convertToDTO(contentAuditRepository.save(audit));
    }

    @Override
    @Transactional
    public ContentAuditDTO approve(Long id, String reason) {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        User auditor = userRepository.findByUsername(username)
                .orElseThrow(() -> new ResourceNotFoundException("User", "username", username));

        ContentAudit audit = contentAuditRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("ContentAudit", "id", id));

        if (!"PENDING".equals(audit.getStatus())) {
            throw new RuntimeException("Content has already been audited");
        }

        audit.setAuditor(auditor);
        audit.setStatus("APPROVED");
        audit.setReason(reason);
        audit.setAuditedAt(LocalDateTime.now());

        return convertToDTO(contentAuditRepository.save(audit));
    }

    @Override
    @Transactional
    public ContentAuditDTO reject(Long id, String reason) {
        if (reason == null || reason.trim().isEmpty()) {
            throw new RuntimeException("Rejection reason is required");
        }

        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        String username = authentication.getName();
        User auditor = userRepository.findByUsername(username)
                .orElseThrow(() -> new ResourceNotFoundException("User", "username", username));

        ContentAudit audit = contentAuditRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("ContentAudit", "id", id));

        if (!"PENDING".equals(audit.getStatus())) {
            throw new RuntimeException("Content has already been audited");
        }

        audit.setAuditor(auditor);
        audit.setStatus("REJECTED");
        audit.setReason(reason);
        audit.setAuditedAt(LocalDateTime.now());

        return convertToDTO(contentAuditRepository.save(audit));
    }

    @Override
    public ContentAuditDTO getAuditById(Long id) {
        return contentAuditRepository.findById(id)
                .map(this::convertToDTO)
                .orElseThrow(() -> new ResourceNotFoundException("ContentAudit", "id", id));
    }

    @Override
    public Page<ContentAuditDTO> getPendingAudits(Pageable pageable) {
        return contentAuditRepository.findByStatus("PENDING", pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<ContentAuditDTO> getAuditsByStatus(String status, Pageable pageable) {
        return contentAuditRepository.findByStatus(status, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<ContentAuditDTO> getAuditsBySubmitter(Long submitterId, Pageable pageable) {
        User submitter = userRepository.findById(submitterId)
                .orElseThrow(() -> new ResourceNotFoundException("User", "id", submitterId));

        return contentAuditRepository.findBySubmitter(submitter, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<ContentAuditDTO> getAuditsByAuditor(Long auditorId, Pageable pageable) {
        User auditor = userRepository.findById(auditorId)
                .orElseThrow(() -> new ResourceNotFoundException("User", "id", auditorId));

        return contentAuditRepository.findByAuditor(auditor, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public Page<ContentAuditDTO> getAuditsByContent(String type, Long contentId, Pageable pageable) {
        return contentAuditRepository.findByTypeAndContentId(type, contentId, pageable)
                .map(this::convertToDTO);
    }

    @Override
    public boolean isContentUnderAudit(String type, Long contentId) {
        return contentAuditRepository.existsByTypeAndContentIdAndStatusNot(type, contentId, "REJECTED");
    }

    private ContentAuditDTO convertToDTO(ContentAudit audit) {
        ContentAuditDTO dto = new ContentAuditDTO();
        dto.setId(audit.getId());
        dto.setType(audit.getType());
        dto.setContentId(audit.getContentId());
        dto.setTitle(audit.getTitle());
        dto.setContent(audit.getContent());
        dto.setSubmitterId(audit.getSubmitter().getId());
        dto.setSubmitterUsername(audit.getSubmitter().getUsername());
        
        if (audit.getAuditor() != null) {
            dto.setAuditorId(audit.getAuditor().getId());
            dto.setAuditorUsername(audit.getAuditor().getUsername());
        }
        
        dto.setStatus(audit.getStatus());
        dto.setReason(audit.getReason());
        dto.setSubmittedAt(audit.getSubmittedAt());
        dto.setAuditedAt(audit.getAuditedAt());
        
        return dto;
    }
} 